package com.shigen.demo.config;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.shigen.demo.bean.Result;
import com.shigen.demo.util.IPUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

@Slf4j
@Aspect
@Component
public class WebAspectConfig {

  @Pointcut("execution(* com.shigen.demo.controller..*(..))")
  private void controllerAspect() {

  }

  @Around(value = "controllerAspect()")
  public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
    RequestAttributes ra = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes sra = (ServletRequestAttributes) ra;
    Objects.requireNonNull(sra);
    HttpServletRequest request = sra.getRequest();
    String ip = IPUtil.getIp(request);
    String requestPath = request.getRequestURI();
    String clazzName = joinPoint.getTarget().getClass().getSimpleName();
    String methodName = joinPoint.getSignature().getName();
    String method = request.getMethod();
    log.info("IP:{} URI:{} method:{} {}.{} 方法：请求参数:{}", ip, requestPath, method, clazzName, methodName, getRequestParam(request, joinPoint));
    long start = System.currentTimeMillis();
    Object result = joinPoint.proceed();
    long end = System.currentTimeMillis() - start;
    if (result instanceof Result) {
      log.info("{}.{}: 总执行耗时:{} ms, result: {}", clazzName, methodName, end, JSON.toJSONString(result));
    } else {
      log.info("{}.{}: 总执行耗时:{} ms", clazzName, methodName, end);
    }
    return result;
  }

  public static String getRequestParam(HttpServletRequest request, ProceedingJoinPoint joinPoint) {
    try {
      String contentType = request.getHeader("Content-Type");
      if (StrUtil.isNotEmpty(contentType) && contentType.contains("application/json")) {
        String[] argNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
        Object[] args = joinPoint.getArgs();
        Map<String, Object> maps = new HashMap(16);

        for (int i = 0; i < args.length; ++i) {
          if (!(args[i] instanceof ServletRequestDataBinder)
              && !(args[i] instanceof HttpServletRequest)
              && !(args[i] instanceof HttpServletResponse)) {
            if (args[i] instanceof MultipartFile) {
              MultipartFile f = (MultipartFile) args[i];
              maps.put(f.getName(), f.getOriginalFilename());
            } else {
              maps.put(argNames[i], args[i]);
            }
          }
        }

        return JSON.toJSONString(maps);
      } else {
        return JSON.toJSONString(request.getParameterMap());
      }
    } catch (Exception e) {
      log.warn("LogAspectConfig.getRequestParam", e);
      return "";
    }
  }
}
